package cn.founder.user.service.impl;

import cn.founder.basic.constant.BaseConstant;
import cn.founder.basic.exception.BusinessException;
import cn.founder.basic.util.AjaxResult;
import cn.founder.basic.util.HttpClientUtils;
import cn.founder.basic.util.MD5Utils;
import cn.founder.basic.util.StrUtils;
import cn.founder.user.domain.Logininfo;
import cn.founder.user.domain.User;
import cn.founder.user.domain.WxUser;
import cn.founder.user.dto.LoginDto;
import cn.founder.user.dto.UserDto;
import cn.founder.user.mapper.LogininfoMapper;
import cn.founder.user.mapper.UserMapper;
import cn.founder.user.mapper.WxUserMapper;
import cn.founder.user.service.ILoginServier;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * 前后端公用登录实现
 */

@Service
public class LoginServierImpl implements ILoginServier {

    @Autowired
    private LogininfoMapper logininfoMapper;

    //注入进行redis数据库操作
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private WxUserMapper wxUserMapper;

    //绑定时候判断用户是否注册过
    @Autowired
    private UserMapper userMapper;


    //登录
    @Override
    public Map<String, Object> accountLogin(LoginDto logindto) {
        //取出前端传来的密码和用户名
        String password = logindto.getPassword();
        String username = logindto.getUsername();
        Integer type = logindto.getType();
        //空校验判断
        if(StringUtils.isEmpty(password)
                || StringUtils.isEmpty(username)){
            throw new BusinessException("请填写正确的信息，谢谢");
        }
        //查询用户登录信息 根据用户名+type查询loginifo表  查询手机 邮箱 用户名
        Logininfo info = logininfoMapper.loadByName(username,type);
        //判断是否存在
        if(info == null){
            throw new BusinessException("用户不存在，请检查信息");
        }
        //查询用户是否被禁用
        if(info.getDisable() == 0){
            throw new BusinessException("用户已被禁用，请联系管理员");
        }
        //如果查询到了用户还要检查密码
            //获得盐值
        String salt = info.getSalt();
            //将现在的密码加盐值  加密后对比 库里的密码和现在密码是否一致
        String byMd5 = MD5Utils.encrypByMd5(password + salt);
        if(!info.getPassword().equals(byMd5)){
            throw new BusinessException("账户或密码错误，请检查信息");
        }
        //密码一致那么存入redis  获得token
        String token = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set(
                token,  //   随机串
                info,  // 账户的信息
                30,  //30分钟过期
                TimeUnit.MINUTES
        );
        //返回信息 token和用户基本信息
        Map<String,Object> map = new HashMap<>();
        map.put("token",token);
        //将用户敏感信息抹除
        info.setPassword(null);
        info.setSalt(null);
        map.put("loginInfo",info);
        return map;
    }




    //微信用户登录
    @Override
    public AjaxResult wechatLogin(Map<String, String> param) {
        //获取code   判断空值
        String code = param.get("code");
        if(StringUtils.isEmpty(code)){
            throw new BusinessException("微信授权登录异常,请稍后再试");
        }
        //根据code获取令牌 =获取accessToken
        // 拼接地址获取TOKEN---获取令牌准备
        String getToken = BaseConstant.GET_TOKEN_URL
                .replace("APPID",BaseConstant.APPID)
                .replace("SECRET",BaseConstant.SECRET)
                .replace("CODE",code);
        //根据拼接地址发送Http请求---真正发送请求获取令牌
        String jsonStr = HttpClientUtils.httpGet(getToken);
        //根据微信返回的信息，从中获取accessToken 和 openid
        JSONObject jsonObject = JSONObject.parseObject(jsonStr);
        String accessToken = jsonObject.getString("access_token");//令牌
        String openId = jsonObject.getString("openid");//openid指扫码人的微信号
        //拿到了opendid查询是否在我平台扫码过  查询xvuser表
        WxUser wxUser = wxUserMapper.loadByOpenId(openId);
        if(wxUser !=null && wxUser.getUser_id() !=null ){
            //都不为空表示在平台扫码过且绑定，直接免密登录
            //查询wxuser表里user_id对应的user表
            Logininfo info = logininfoMapper.loadByUserId(wxUser.getUser_id());
            //获得token串   根据xvuser表中 已查询到对应的user信息  存入redis
            String token = UUID.randomUUID().toString();
            redisTemplate.opsForValue().set(
                    token,  //   随机串
                    info,  // 账户的信息
                    30,  //30分钟过期
                    TimeUnit.MINUTES
            );
            //返回信息 token和用户基本信息
            Map<String,Object> map = new HashMap<>();
            map.put("token",token);
            //将用户敏感信息抹除
            info.setPassword(null);
            info.setSalt(null);
            map.put("loginInfo",info);
            //返回接口要的ajaxresult对象
            return AjaxResult.myself().setResultObj(map);
        }
        //如果查询不到信息或没有绑定，直接走绑定流程
        //将令牌和openid一起带过去,如果根本没信息，方便后续生成pethome账号后 从vx获取用户资料再绑定
        String binderParams = "?accessToken="+accessToken+"&openId="+openId;
        return AjaxResult.fail(binderParams);
    }

    //微信帐号绑定
    @Override
    public Map<String, Object> binderWechat(Map<String, String> params) {
        //用户绑定请求过来了  校验信息
        String phone = params.get("phone");
        String verifyCode = params.get("verifyCode");
        String accessToken = params.get("accessToken");
        String openId = params.get("openId");
        //校验判断
        if(StringUtils.isEmpty(phone)
                || StringUtils.isEmpty(verifyCode)
                || StringUtils.isEmpty(accessToken)
                || StringUtils.isEmpty(openId) ){
            //如果有空值直接报错
            throw new BusinessException("请填写完整信息！");
        }
        //判断验证码是否为空  是否正确
        Object codeobj = redisTemplate.opsForValue()
                //先通过 注册的头+手机号作为key查询redis 验证码是否过期
                .get(BaseConstant.BUSINESS_TYPE_BINDER + phone);
        if(codeobj == null){
            throw new BusinessException("验证码已过期请重新获取");
        }
        //判断输入的验证码是否正确
        String code = codeobj.toString().split(":")[0];
        //不区分大小写 比对验证码
        if(!code.equalsIgnoreCase(verifyCode)){
            throw new BusinessException("验证码错误，请重新输入");
        }
        //判断用户手机号是否注册过
        User user = userMapper.loadByPhone(phone);
        Logininfo loginInfo = null;
        //如果注册过 直接绑定微信信息，再绑定平台帐号
        if(user!=null){
            loginInfo = logininfoMapper.loadByUserId(user.getId());
        }else {
            //没有注册过帐号  直接生成t_user和t_logininfo表信息进行绑定(注册)
            //-首先保存logininfo数据  创建一个方法
            //把userDto的数据传递给User
            user = userDto2User(phone);
            //把user的数据给 logininfo对象
            loginInfo = user2loininfo(user);
            //开始保存登录logininfo数据
            loginInfo.setType(1);//设置type为1   必定是前端用户
            logininfoMapper.save(loginInfo);
            //将返回的自增id重新设置
            user.setLogininfo_id(loginInfo.getId());
            //保存user数据
            userMapper.save(user);
        }
        //使用令牌和openid 从微信获取用户信息  绑定pethome帐号
        String wxUserUrl = BaseConstant.GET_USER_URL
                .replace("ACCESS_TOKEN", accessToken)
                .replace("OPENID", openId);
        //拼接好地址发送http请求获取------真正获取用户信息
        String wxUserMsg = HttpClientUtils.httpGet(wxUserUrl);
        //将获取到的WX用户信息保存至wxuser表中  下面使用工具类转换微信用户信息
        WxUser wxUser = initWxUser(wxUserMsg, user);
        wxUserMapper.save(wxUser);//保存wx用户信息至WXUSER表中
        //信息已保存完毕 免密登录
        String token = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set(
                token,  //   随机串
                loginInfo,  // 账户的信息
                30,  //30分钟过期
                TimeUnit.MINUTES
        );
        //返回信息 token和用户基本信息
        Map<String,Object> map = new HashMap<>();
        map.put("token",token);
        //将用户敏感信息抹除
        loginInfo.setPassword(null);
        loginInfo.setSalt(null);
        map.put("loginInfo",loginInfo);
        //返回接口要的ajaxresult对象
        return map;
    }

    //使用工具类转换微信用户信息
    private WxUser initWxUser(String wxUserTmp, User user) {
        JSONObject jsonObject = JSONObject.parseObject(wxUserTmp);
        WxUser wxUser =  new WxUser();
        wxUser.setUser_id(user.getId());//绑定用户
        wxUser.setOpenid(jsonObject.getString("openid"));
        wxUser.setNickname(jsonObject.getString("nickname"));
        wxUser.setSex(jsonObject.getInteger("sex"));
        wxUser.setAddress(null);
        wxUser.setHeadimgurl(jsonObject.getString("headimgurl"));
        wxUser.setUnionid(jsonObject.getString("unionid"));
        return wxUser;
    }



    private Logininfo user2loininfo(User user) {
        //声明一个对象
        Logininfo info = new Logininfo();
        //把user的参数 复制给info
        BeanUtils.copyProperties(user,info);
        //返回info
        return info;
    }


    //这是上面的方法
    private User userDto2User(String phone) {
        //声明一个返回对象
        User user = new User();
        //设置用户名和手机号
        user.setUsername(phone);
        user.setPhone(phone);
        user.setEmail(null);
        //获取一个新的盐值
        String salt = StrUtils.getComplexRandomString(32);
        //将注册的手机号和盐值一起加密获得密码
        String psdbyMd5 = MD5Utils.encrypByMd5(phone + salt);
        //设置盐值和密码
        user.setSalt(salt);
        //设置密码
        user.setPassword(psdbyMd5);
        //设置完成后返回对象
        return user;
    }
}
